<template>
  <div>
    <div class="canvasTitle">画布</div>
    <div class="canvas" @dragover.prevent @drop="handleDrop" ref="canvasRef">
      <div class="canvasBlock" :class="isGrid ? 'showGrid' : ''" />
      <div class="topContent">
        <div class="topIcon" />
      </div>
      <svg width="100%" height="100%">
        <line
          v-for="(line, index) in lines"
          :key="index"
          :x1="line.x1"
          :y1="line.y1"
          :x2="line.x2"
          :y2="line.y2"
          stroke="red"
        />
      </svg>
      <div
        v-for="(element, index) in elements"
        :key="element.id"
        :class="[
          'canvas-element',
          element.type === EQUIP_TYPE.LINE && element.y === 40
            ? 'customLineBar'
            : '',
          isEditDrag ? '' : 'pointerEventNone',
        ]"
        :style="{
          top: element.y + 'px',
          left: element.x + 'px',
        }"
        @mousedown="startDrag($event, index, element)"
        @mouseup="stopDrag(element)"
        @mouseenter="element.hovering = true"
        @mouseleave="handleMouseLeave(element)"
        :draggable="false"
      >
        <!-- 线段 -->
        <div v-if="element.type === EQUIP_TYPE.LINE" class="line">
          <div class="lineName">
            <span v-if="!element.showEditName"> {{ element.lineName }} </span>
            <a-input
              v-else
              v-model:value="element.lineName"
              class="nameInput"
              placeholder="请输入"
              size="small"
            />
            <EditOutlined
              @click="handleEditName(index)"
              v-if="!element.showEditName"
              class="editIcon"
            />
            <CheckOutlined
              @click="handleSaveName(index)"
              v-if="element.showEditName"
              class="editIcon"
            />
          </div>
          <span
            class="customLine"
            :style="{
              width: element?.width + 'px',
              height: element.height + 'px',
            }"
          />
        </div>
        <!-- 普通器部件 -->
        <div
          v-if="
            element.type !== EQUIP_TYPE.LINE &&
            element.type !== EQUIP_TYPE.CHONG_DIAN_ZHUANG &&
            element.type !== EQUIP_TYPE.JI_ZHUANG_XIANG
          "
          :class="[
            element.isChildEquip || COMMON_TYPE.includes(element.type)
              ? 'isChildEquip'
              : '',
          ]"
          :style="{
            backgroundImage: `url(${element.url})`,
            backgroundRepeat: 'no-repeat',
            backgroundSize: 'contain',
            width: '50px',
            height: '50px',
          }"
        />
        <!-- 储充项目 充电桩 -->
        <div
          v-if="element.type === EQUIP_TYPE.CHONG_DIAN_ZHUANG"
          class="chongDianZhuang"
          :style="{
            backgroundImage: `url(${element.url})`,
            backgroundRepeat: 'no-repeat',
            backgroundSize: 'contain',
          }"
        >
          <div class="name linkName">{{ element.linkName }}</div>
          <div class="name blockName1">{{ element.blockName1 }}</div>
          <div class="name blockName2">{{ element.blockName2 }}</div>
          <div class="name charge1">{{ element.charge1 }}</div>
          <div class="name charge2">{{ element.charge2 }}</div>
        </div>
        <!-- 集装箱项目 -->
        <div
          v-if="element.type === EQUIP_TYPE.JI_ZHUANG_XIANG"
          class="jiZhuangXiang"
          :class="{
            jiZhuangXiangWithClusters: element.children.some(
              (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
            ),
          }"
          :style="{
            position: 'relative',
            width: element.children.some(
              (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
            )
              ? 'auto'
              : '50px',
            height: element.children.some(
              (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
            )
              ? 'auto'
              : '50px',
          }"
        >
          <!-- 只有有电池簇子元素时才显示电池簇，否则显示原有图标 -->
          <template
            v-if="
              element.children.some((child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER)
            "
          >
            <div class="jiZhuangXiangTitle">{{ element.linkName }}</div>
            <div class="batteryClusterWrapper">
              <div class="jiZhuangXiangBorder">
                <a-popconfirm
                  title="是否删除该器部件？"
                  ok-text="是"
                  cancel-text="否"
                  @confirm="removeElement(element.id, element.systemId, element.type)"
                  @cancel="handleCancelDelete(element)"
                  @openChange="
                    handleDeleteConfirmVisibleChange(element, $event)
                  "
                >
                  <CloseOutlined
                    :class="[
                      'jiZhuangXiangcloseButton',
                      element.type === EQUIP_TYPE.LINE ? 'closeButtonLine' : '',
                    ]"
                  />
                </a-popconfirm>
              </div>
              <!-- 这里渲染 children 中的电池簇 -->
              <div
                v-for="cluster in element.children.filter(
                  (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
                )"
                :key="cluster.id"
                class="batteryCluster"
                :style="{
                  backgroundImage: `url(${BATTERY_CLUSTER_ICON})`,
                }"
                @click.stop="handleBatteryClusterClick(element)"
              >
                <div class="batteryClusterLabel">{{ cluster.name }}</div>
              </div>
            </div>
          </template>
          <template v-else>
            <div
              class="jiZhuangXiangIcon"
              :style="{
                backgroundImage: `url(${element.url})`,
                backgroundRepeat: 'no-repeat',
                backgroundSize: 'contain',
                width: '50px',
                height: '50px',
              }"
            >
              <a-popconfirm
                title="是否删除该器部件？"
                ok-text="是"
                cancel-text="否"
                @confirm="removeElement(element.id, element.systemId, element.type)"
                @cancel="handleCancelDelete(element)"
                @openChange="
                  handleDeleteConfirmVisibleChange(element, $event)
                "
              >
                <CloseOutlined :class="['jiZhuangXiangcloseButton']" />
              </a-popconfirm>
            </div>
          </template>
        </div>
        <div
          v-if="
            element.type !== EQUIP_TYPE.LINE &&
            element.type !== EQUIP_TYPE.CHONG_DIAN_ZHUANG
          "
          class="canvasElementName"
        >
          {{ element.name }}
        </div>
        <div
          v-if="
            element.type !== EQUIP_TYPE.LINE &&
            element.type !== EQUIP_TYPE.COMMON &&
            element.type !== EQUIP_TYPE.FU_ZAI &&
            !element.isChildEquip &&
            !element.systemId
          "
          :class="[
            'canvasElementTips',
            element.type === EQUIP_TYPE.CHONG_DIAN_ZHUANG ? 'cdzTips' : '',
          ]"
        >
          请先完成右侧配置项
        </div>
        <a-popconfirm
          title="是否删除该器部件？"
          ok-text="是"
          cancel-text="否"
          @confirm="removeElement(element.id, element.systemId, element.type)"
          @cancel="handleCancelDelete(element)"
          @openChange="handleDeleteConfirmVisibleChange(element, $event)"
        >
          <CloseOutlined
            v-if="
              (element.hovering || element.showDeleteConfirm) &&
              stionConfigState.isEditDrag &&
              element.type !== EQUIP_TYPE.JI_ZHUANG_XIANG &&
              element.y !== 40 && // 顶线不能删除
              !element.children.length // 没有子级器部件
            "
            :class="[
              'closeButton',
              element.type === EQUIP_TYPE.LINE ? 'closeButtonLine' : '',
            ]"
          />
        </a-popconfirm>
      </div>
    </div>
  </div>
</template>
<script setup>
;
import { useStionConfigStore } from "@/stores/stationConfig";
import {
  CHILD_EQUIP,
  CHILD_EQUIP_KEYS,
  EQUIP_TYPE,
  COMMON_TYPE,
} from "@/constants/stationConfig";
import { uniqueId, now, cloneDeep, uniqBy, forEach } from "lodash-es";
const props = defineProps({
  topologyMap: {
    type: String,
  },
  disabled: {
    type: Boolean,
  },
  rowData: {
    type: Object,
  },
  isGrid: {
    type: Boolean,
  },
});
const isChargeProject = computed(() => props.rowData.isChargeProject);
const elements = ref([]);
watch(
  () => props.topologyMap,
  (val) => {
    if (val.length) {
      initDragData(JSON.parse(val));
    } else {
      elements.value = [
        {
          id: "topLine",
          type: EQUIP_TYPE.LINE,
          x: 120,
          y: 40,
          children: [],
          lineName: "",
          showDeleteConfirm: false,
          height: 4,
          width: 2000,
        },
      ];
    }
  },
  { deep: true, immediate: true }
);
const {
  stionConfigState,
  changeEquipType,
  changeDragData,
  changeConfigData,
  changeDragging,
} = useStionConfigStore();
const dragging = computed(() => stionConfigState.dragging);
const isEditDrag = computed(() => stionConfigState.isEditDrag);
const $api = inject("$api");
const lines = ref([]);
const canvasRef = ref(null);
let dragIndex = ref(-1);
let offsetX = ref(0);
let offsetY = ref(0);
const DISTANCE_THRESHOLD = 120; // 拖拽起作用区间距离
const BATTERY_CLUSTER_ICON =
  "https://ngp-cloud.oss-cn-shenzhen.aliyuncs.com/dev/2025-01-19/f9968a662f6ab1a71c6a.png"; // 电池簇图片
const emits = defineEmits([
  "validateDragPass",
  "handleSaveDragConfig",
  "getElements",
]);
const handleEditName = (index) => {
  elements.value[index].showEditName = true;
};
const handleSaveName = (index) => {
  elements.value[index].showEditName = false;
};

// 处理电池簇点击事件
const handleBatteryClusterClick = (jiZhuangXiangElement) => {
  // 设置当前选中的器部件为集装箱
  changeDragData(jiZhuangXiangElement);
  changeEquipType(jiZhuangXiangElement.type);

  // 设置配置数据
  changeConfigData({
    ...stionConfigState.configData,
    isEdit: false,
  });
};
// 处理放置新元素到画布
const handleDrop = async (event, isChildEquip = false, childEquip) => {
  changeDragging(false);
  await nextTick();
  const equipData = stionConfigState.equipData;
  const dragData = stionConfigState.dragData;
  const url = equipData.url; // 获取到拖拽的图标url

  let newElement = {};
  if (isChildEquip) {
    newElement = {
      id: event.id, // 为元素分配唯一ID
      name: event.name,
      url: event.url,
      x: event.offsetX,
      y: event.offsetY,
      children: [],
      hovering: false,
      showDeleteConfirm: false,
      type: event.type || equipData.modelType,
      systemType: event.type || equipData.modelType,
      [`${childEquip}`]: 1,
      isChildEquip: 1,
    };
    newElement.parentId = dragData.systemId;
    const search = (data) => {
      for (let item of data) {
        // 当找到对应的 parentId 时，将 newElement 添加到其 children 中
        if (item.systemId === newElement.parentId) {
          item.children.unshift(newElement);
          return true; // 找到并添加后，可以终止递归
        }
        // 如果有 children，则进行递归搜索
        if (item.children && Array.isArray(item.children)) {
          const found = search(item.children);
          if (found) {
            return true; // 如果在子节点中找到，也可以终止递归
          }
        }
      }
      return false; // 如果没有找到 parentId
    };
    // 启动搜索
    search(elements.value);
  } else {
    // 通过拖拽，新增器部件
    const rect = event.currentTarget.getBoundingClientRect();
    // 计算相对于目标容器的精确坐标
    const correctX = event.clientX - rect.left;
    const correctY = event.clientY - rect.top;
    const uId = uniqueId() + now();
    newElement = {
      id: uId.substring(uId.length - 5, uId.length), // 为元素分配唯一ID
      name: equipData.deviceName,
      url,
      x: correctX - 25,
      y: correctY - 25,
      children: [],
      hovering: false,
      showDeleteConfirm: false,
      type: equipData.modelType,
    };
    if (equipData.modelType === EQUIP_TYPE.LINE) {
      newElement.lineName = "";
      newElement.height = 4;
      newElement.width = 200;
    }
    if (equipData.modelType === EQUIP_TYPE.CHONG_DIAN_ZHUANG) {
      newElement.x = newElement.x - 120;
    }
    const { parentIndex, parentId } = findClosestParent(correctX, correctY);
    if (parentIndex !== -1) {
      newElement.parentId = parentId;
      elements.value[parentIndex].children.push(newElement);
    }
    // 注意，以下两个拖拽数据的状态更新，只在新增器部件时更新，右侧配置新增的子器部件时不更新
    changeEquipType(equipData.modelType);
    changeDragData(newElement);
  }
  elements.value.push(newElement);
  emits("getElements", elements.value);
  connectLines();
  changeConfigData({
    ...stionConfigState.configData,
    isEdit: true,
  });
};
const jiZhuangXiangBlockNum = ref(0); // 集装箱项目 电池簇数量
const handleSaveDragConfig = () => {
  const childEquipKeys = CHILD_EQUIP_KEYS;
  const { dragData, configData, equipData } = stionConfigState;
  jiZhuangXiangBlockNum.value = configData.blockNum;
  const search = (data) => {
    for (let item of data) {
      if (item.id === dragData.id) {
        // 把右侧配置的名称，更新到拖拽的元素
        item.name = configData.name;
        // 只在configData.systemId有值时才更新，避免覆盖原有的systemId
        if (configData.systemId) {
          item.systemId = configData.systemId; // 传给后端的 器部件id
        }
        item.systemType = item.type || equipData.modelType; // 传给后端的 器部件type
        if (item.type === EQUIP_TYPE.LINE) {
          item.width = configData.width;
          item.height = configData.height;
        }
        if (item.type === EQUIP_TYPE.CHONG_DIAN_ZHUANG) {
          item.linkName = configData.linkName;
          item.blockName1 = configData.blockIdList[0]?.blockName;
          item.blockName2 = configData.blockIdList[1]?.blockName;
          item.charge1 = configData.chargingList[0]?.chargingGunName;
          item.charge2 = configData.chargingList[1]?.chargingGunName;
        }
        // 处理集装箱项目的电池簇
        if (item.type === EQUIP_TYPE.JI_ZHUANG_XIANG) {
          item.linkName = configData.linkName;
          // 先清除现有的电池簇子元素
          item.children = item.children.filter(
            (child) => child.type !== EQUIP_TYPE.BATTERY_CLUSTER
          );
          // 如果有电池簇配置数据，使用配置的数据
          if (
            configData.blockIdList &&
            configData.blockIdList.length > 0
          ) {
            configData.blockIdList.forEach((clusterConfig, index) => {
              const uId = uniqueId() + now();
              const batteryCluster = {
                id: uId.substring(uId.length - 5, uId.length),
                name: clusterConfig.blockName, // 使用用户配置的名称
                idx: clusterConfig.blockIdx, // 电池簇唯一标识
                orderNum: clusterConfig.orderNum, // 资产设备编号
                assetCode: clusterConfig.blockAsserCode, // 电池簇资产编码
                type: EQUIP_TYPE.BATTERY_CLUSTER,
                x:
                  item.x +
                  (index - (configData.blockIdList.length - 1) / 2) * 100, // 基于父元素中心点左右铺开
                y: item.y + 60, // 距离父元素下方60px
                children: [],
                hovering: false,
                showDeleteConfirm: false,
                parentId: item.systemId || item.id,
                isChildEquip: 1,
                // 设置电池簇的systemId，从configData.children.blockIds中获取
                systemId: configData.children?.blockIds?.[index] || null,
              };
              item.children.push(batteryCluster);
            });
          } else if (configData.blockNum > 0) {
            // 如果没有电池簇配置数据，但有 blockNum，则使用默认生成方式
            for (let n = 1; n <= configData.blockNum; n++) {
              const uId = uniqueId() + now();
              const batteryCluster = {
                id: uId.substring(uId.length - 5, uId.length),
                name: `${n}`,
                type: EQUIP_TYPE.BATTERY_CLUSTER,
                x: item.x + (n - 1 - (configData.blockNum - 1) / 2) * 100, // 基于父元素中心点左右铺开
                y: item.y + 60, // 距离父元素下方60px
                children: [],
                hovering: false,
                showDeleteConfirm: false,
                parentId: item.systemId || item.id,
                isChildEquip: 1,
                // 设置电池簇的systemId，从configData.children.blockIds中获取
                systemId: configData.children?.blockIds?.[n - 1] || null,
              };
              item.children.push(batteryCluster);
            }
          }
        }
      }
      // 以下是处理衍生器部件的名称变更
      if (item.parentId === dragData.systemId) {
        if (item.isGatewayMeter) {
          item.name = configData.gatewayName;
        }
        if (item.isBreaker) {
          item.name = configData.breakerName;
        }
        if (item.isRingMainMeter) {
          item.name = configData.ringMeterName;
        }
        if (item.isAccountMeter) {
          item.name = configData.accountMeterName;
        }
      }

      // 如果有 children，则进行递归搜索
      if (item.children && Array.isArray(item.children)) {
        search(item.children);
      }
    }
  };
  // 启动搜索
  search(elements.value);
  // 递归查找子器部件的函数
  const findChildEquipRecursively = (elementsList, parentSystemId, parentId, childEquipType) => {
    let found = [];
    const search = (elements) => {
      for (const item of elements) {
        if (
          (item.parentId === parentSystemId || item.parentId === parentId) && 
          item[childEquipType] === 1
        ) {
          found.push(item);
        }
        if (item.children && Array.isArray(item.children)) {
          search(item.children);
        }
      }
    };
    search(elementsList);
    return found;
  };

  childEquipKeys.forEach((childEquip, index) => {
    if (configData?.[childEquip]) {
      // 查找所有可能的子器部件
      const existingChildEquip = findChildEquipRecursively(
        elements.value, 
        dragData.systemId, 
        dragData.id, 
        childEquip
      );
      
      if (existingChildEquip.length === 0) {
        // 没有对应的子器部件，再新增
        const uId = uniqueId() + now() + CHILD_EQUIP[childEquip].type;
        const nameKey = CHILD_EQUIP[childEquip].nameKey;
        handleDrop(
          {
            id: uId.substring(uId.length - 5, uId.length), // 为元素分配唯一ID
            name: configData[nameKey],
            url: CHILD_EQUIP[childEquip].url,
            offsetX: dragData.x + (index + 1) * 80,
            offsetY: dragData.y,
            children: [],
            hovering: false,
            showDeleteConfirm: false,
            type: CHILD_EQUIP[childEquip].type,
          },
          true,
          childEquip
        );
      }
    } else {
      const id = handleFindChildEquipId(
        elements.value,
        stionConfigState.dragData.systemId,
        childEquip
      );
      if (id.length) {
        for (const item of id) {
          removeElement(item);
        }
      }
    }
  });

  // 更新连接线
  connectLines();
  emits("getElements", elements.value); // 上报拖拽数据
};
// 遍历查找子器部件的id
const handleFindChildEquipId = (elememts, parentId, type) => {
  let result = [];
  const search = (elememts) => {
    for (const item of elememts) {
      // 检查当前项的 CHILD_EQUIP_KEYS常量 是否为 1 和 parentId 是否匹配
      if (
        item[type] === 1 &&
        (item.parentId === parentId || item.id === parentId)
      ) {
        result.push(item.systemId || item.id); // 收集符合条件的 id
      }
      // 如果有 children，则进行递归搜索
      if (item.children && Array.isArray(item.children)) {
        search(item.children);
      }
    }
  };
  // 启动搜索
  search(elememts);
  return [...new Set(result)]; // 返回符合条件的所有 id
};
// 查找最近的父元素索引
const findClosestParent = (offsetX, offsetY) => {
  let parentIndex = -1;
  let parentId = null;
  let closestDistance = DISTANCE_THRESHOLD;

  for (let i = 0; i < elements.value.length; i++) {
    const element = elements.value[i];
    const distance = Math.hypot(
      element.x + 25 - offsetX,
      element.y + 25 - offsetY
    );
    if (distance <= closestDistance) {
      // 只考虑符合距离阈值
      closestDistance = distance;
      parentIndex = i;
      parentId = element.systemId;
    }
  }
  return { parentIndex, parentId };
};
const uniqueLines = (lines) => {
  // 去除重复的线
  let horizontalLines = [];
  let verticalLines = [];
  lines.forEach((line) => {
    if (line.y1 === line.y2) {
      const y = line.y1;
      const xStart = Math.min(line.x1, line.x2);
      const xEnd = Math.max(line.x1, line.x2);
      const length = xEnd - xStart;
      const existingLine = horizontalLines.find(
        (l) =>
          l.y1 === y &&
          ((l.x1 <= xStart && l.x2 >= xEnd) || (l.x1 >= xStart && l.x2 <= xEnd))
      );
      if (!existingLine || existingLine.length < length) {
        horizontalLines = horizontalLines.filter(
          (l) =>
            !(
              l.y1 === y &&
              ((l.x1 <= xStart && l.x2 >= xEnd) ||
                (l.x1 >= xStart && l.x2 <= xEnd))
            )
        );
        horizontalLines.push({ x1: xStart, y1: y, x2: xEnd, y2: y, length });
      }
    } else if (line.x1 === line.x2) {
      const x = line.x1;
      const yStart = Math.min(line.y1, line.y2);
      const yEnd = Math.max(line.y1, line.y2);
      const length = yEnd - yStart;
      const existingLine = verticalLines.find(
        (l) =>
          l.x1 === x &&
          ((l.y1 <= yStart && l.y2 >= yEnd) || (l.y1 >= yStart && l.y2 <= yEnd))
      );
      if (!existingLine || existingLine.length < length) {
        verticalLines = verticalLines.filter(
          (l) =>
            !(
              l.x1 === x &&
              ((l.y1 <= yStart && l.y2 >= yEnd) ||
                (l.y1 >= yStart && l.y2 <= yEnd))
            )
        );
        verticalLines.push({ x1: x, y1: yStart, x2: x, y2: yEnd, length });
      }
    }
  });
  return [...horizontalLines, ...verticalLines];
};
// 更新连接线,根据父子元素连接线
const connectLines = async () => {
  lines.value = []; // 重置连接线
  const drawParentChildLines = (element) => {
    // 只有在直接父子关系中绘制连接线
    for (const child of element.children) {
      if (element.type !== EQUIP_TYPE.LINE && child.type !== EQUIP_TYPE.LINE) {
        drawLine(element, child); // 绘制父亲到子级的线
        drawParentChildLines(child); // 递归到子级，确保子级继续绘制
      }
    }
  };
  let lineArr = elements.value.filter((elem) => elem.type === EQUIP_TYPE.LINE);
  const cloneLineArr = cloneDeep(lineArr);
  for (const element of elements.value) {
    // 如果此元素是顶级元素（没有父元素），则绘制连接线到顶部
    if (
      !element.parentId &&
      element.parentId !== 0 &&
      element.type !== EQUIP_TYPE.LINE
    ) {
      // 找出在器部件上方位置的线
      lineArr = cloneLineArr.filter(
        (line) =>
          (element.x >= line.x - 25 && element.x <= line.x + line.width - 25) ||
          (line.y === 40 && line.x === undefined)
      );

      if (lineArr.length) {
        const lineClosestToChild = lineArr.reduce((closest, current) => {
          const currentDiff = Math.abs(current.y - element.y + 25);
          const closestDiff = Math.abs(closest.y - element.y + 25);
          return currentDiff < closestDiff ? current : closest;
        });

        drawLine({ x: element.x, y: lineClosestToChild.y - 50 }, element); // 连接线到顶部电线
      }
    }
    // 仅绘制此元素的子级，防止跨代连接线
    drawParentChildLines(element);
  }

  // 为集装箱的电池簇绘制连线
  elements.value.forEach((element) => {
    if (element.type === EQUIP_TYPE.JI_ZHUANG_XIANG && element.children) {
      const batteryClusters = element.children.filter(
        (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
      );
      batteryClusters.forEach((cluster) => {
        // 从电池簇到集装箱的连线
        const clusterX = cluster.x + 25; // 电池簇中心X
        const clusterY = cluster.y; // 电池簇顶部Y
        const targetX = element.x + 25; // 集装箱中心X
        const targetY = element.y + 25; // 集装箱中心Y
        // 绘制连线：先竖直，再水平
        lines.value.push({
          x1: clusterX,
          y1: clusterY,
          x2: clusterX,
          y2: targetY,
        });
        lines.value.push({
          x1: clusterX,
          y1: targetY,
          x2: targetX,
          y2: targetY,
        });
      });
    }
  });

  lines.value = uniqueLines(lines.value); // 去重
};

// 绘制连接线
const drawLine = (parent, child, guanKouBiao) => {
  let startX = parent.x + 25; // 父元素中心X
  const startY = parent.y + 25; // 父元素中心Y
  let endX; // 子元素中心X
  let endY; // 子元素中心Y
  if (child.type === EQUIP_TYPE.LINE) {
    endX = parent.x + 25;
    endY = child.y;
  } else if (child.type === EQUIP_TYPE.CHONG_DIAN_ZHUANG) {
    endX = child.x + 150;
    endY = child.y;
  } else if (child.type === EQUIP_TYPE.BATTERY_CLUSTER) {
    endX = child.x + 25;
    endY = child.y;
  } else {
    endX = child.x + 25;
    endY = child.y + 25;
  }
  const addLine = (x1, y1, x2, y2) => {
    lines.value.push({
      x1,
      y1,
      x2,
      y2,
    });
  };
  if (startX === endX) {
    // 竖直线
    const yAdjustment = startY < endY ? 25 : -25;
    addLine(startX, startY + yAdjustment, endX, endY);
  } else if (startY === endY) {
    // 水平线
    const xAdjustment = startX < endX ? 25 : -25;
    addLine(startX + xAdjustment, startY, endX, endY);
  } else {
    // 计算相对方向并先绘制横线，再绘制竖线
    addLine(startX, startY, endX, startY); // 添加横线
    addLine(endX, startY, endX, endY); // 添加竖线
  }
};
// 开始拖拽
const startDrag = async (event, index, element) => {
  if (props.disabled) {
    return;
  }
  // event.preventDefault();
  dragIndex.value = index;
  offsetX.value = event.clientX - elements.value[index].x;
  offsetY.value = event.clientY - elements.value[index].y;
  window.addEventListener("mousemove", onMouseMove);
  window.addEventListener("mouseup", stopDrag);
};
// 停止拖拽
const stopDrag = (element) => {
  // dragging.value = false;
  changeDragging(false);
  dragIndex.value = -1;
  window.removeEventListener("mousemove", onMouseMove);
  window.removeEventListener("mouseup", stopDrag);
  changeDragData(element);
  // changeEquipType(element.type);
  if (element.isChildEquip === 1) {
    changeEquipType("COMMON");
  } else {
    changeEquipType(element.type);
  }

  if (element.type === EQUIP_TYPE.LINE) {
    changeConfigData({
      width: element.width,
      height: element.height,
      type: EQUIP_TYPE.LINE,
      isEdit: false,
    });
  } else {
    changeConfigData({
      ...stionConfigState.configData,
      isEdit: false,
    });
  }

  // 更新连接线
  connectLines();
  emits("getElements", elements.value); // 上报拖拽数据
};

// 鼠标移动事件
const onMouseMove = async (event) => {
  if (dragging && dragIndex.value !== -1) {
    const element = elements.value[dragIndex.value];
    // 更新当前元素的位置
    element.x = event.clientX - offsetX.value;
    element.y = event.clientY - offsetY.value;

    const setPosition = (arr, targetId) => {
      arr.forEach((item) => {
        // 检查当前对象是否满足条件
        if (item.id === targetId) {
          const newX = event.clientX - offsetX.value;
          const newY = event.clientY - offsetY.value;
          item.x = newX;
          item.y = newY;

          // 如果是集装箱，需要更新其电池簇子元素的位置
          if (item.type === EQUIP_TYPE.JI_ZHUANG_XIANG && item.children) {
            const batteryClusters = item.children.filter(
              (child) => child.type === EQUIP_TYPE.BATTERY_CLUSTER
            );
            batteryClusters.forEach((cluster, index) => {
              const totalClusters = batteryClusters.length;
              cluster.x = newX + (index - (totalClusters - 1) / 2) * 100;
              cluster.y = newY + 60;
            });
          }
        }
        // 如果当前对象有子元素，则递归搜索子元素
        if (item.children && item.children.length > 0) {
          setPosition(item.children, element.id);
        }
      });
      return arr;
    };
    // setPosition 是为了拖动过程中，把x y坐标信息赋值到elements对应的id数据上，达到更新效果
    const arr = setPosition(elements.value, element.id);
    // 更新连接线
    await nextTick();
    elements.value = arr;
    connectLines();
  }
};
// 从画布中删除指定ID的元素及其所有层级对应的子元素
const removeElement = async (id, systemId, type) => {
  // 找到要删除的元素及其子元素的所有ID
  const idsToDelete = getAllIdsToDelete(elements.value, id, "id");
  // 找到要删除的元素及其子元素的所有systemid (后端需要调删除接口传systemid)
  const executeDeleteFlow = async () => {
    // 统一删除逻辑
    elements.value = deleteElementsById(elements.value, idsToDelete);
    emits("getElements", elements.value); // 上报拖拽数据
    // 连接器重绘逻辑
    connectLines();
    changeEquipType("");
    // 删除后需要保存拓扑图，以免器部件在后端已经删除，前端没保存到
    await $api.stationTopologyMapSave(
      {
        stationId: props.rowData.stationId,
        frontData: JSON.stringify({ data: elements.value }),
      },
      "post"
    );
  };

  // 重置删除确认状态
  const targetElement = elements.value.find((el) => el.id === id);
  if (targetElement) {
    targetElement.showDeleteConfirm = false;
  }

  if (systemId) {
    const res = await $api[
      isChargeProject.value
        ? "chargingStationTopologyMap"
        : "stationTopologyMap"
    ](
      {
        stationId: props.rowData.stationId,
        id: systemId,
        modelType: type
      },
      "delete"
    );

    if (res?.code === 0) {
      await executeDeleteFlow();
    }
  } else {
    await executeDeleteFlow();
  }
};
// 查找所有需要删除的ID
const getAllIdsToDelete = (elementsList, id, idType) => {
  const idsToDelete = new Set();
  // 递归查找元素及其子元素
  const collectIds = (elementsList) => {
    for (const elem of elementsList) {
      if (elem.id === id) {
        // 添加当前元素的 ID
        idsToDelete.add(elem[idType]);
        if (elem.type === EQUIP_TYPE.LINE) {
          // 这里注意：如果是删除线段，只删除线段本身即可，不需要删除子元素
          return;
        }
        // 收集当前元素的所有子 ID
        const collectChildrenIds = (children) => {
          for (const child of children) {
            idsToDelete.add(child[idType]); // 添加子元素 ID
            if (child.children && child.children.length > 0) {
              // 如果有子元素，则递归收集
              collectChildrenIds(child.children);
            }
          }
        };
        // 开始收集子元素的 ID
        if (elem.children && elem.children.length > 0) {
          collectChildrenIds(elem.children);
        }
      }
      // 递归查找当前元素的子元素
      if (elem.children && elem.children.length > 0) {
        collectIds(elem.children);
      }
    }
  };
  collectIds(elementsList);
  return Array.from(idsToDelete); // 转换为数组返回
};
// 从数组中删除指定ID的元素，包含其子元素
const deleteElementsById = (elementsList, idsToDelete) => {
  return elementsList.reduce((acc, elem) => {
    // 如果当前元素的ID在待删除集合中，则不加入结果
    if (!idsToDelete.includes(elem.id)) {
      const newElem = { ...elem }; // 创建新元素对象
      // 检查并递归删除子元素
      if (elem.children && elem.children.length > 0) {
        newElem.children = deleteElementsById(elem.children, idsToDelete);
      }
      acc.push(newElem); // 添加不需要删除的元素到结果数组
    }
    return acc; // 返回当前累积的结果
  }, []);
};
// 处理鼠标离开事件
const handleMouseLeave = (element) => {
  element.hovering = false;
};

// 处理删除确认弹窗显示状态变化
const handleDeleteConfirmVisibleChange = (element, visible) => {
  element.showDeleteConfirm = visible;
};

// 处理取消删除
const handleCancelDelete = (element) => {
  element.showDeleteConfirm = false;
};
const initDragData = ({ data }) => {
  // 用于恢复的逻辑
  if (data) {
    elements.value = []; // 这里先清空
    data.forEach((position) => {
      // 确保每个元素都有 showDeleteConfirm 属性
      elements.value.push({
        ...position,
        showDeleteConfirm: position.showDeleteConfirm || false,
      });
    });
    if (!elements.value.some((item) => item.id === "topLine")) {
      elements.value.unshift({
        id: "topLine",
        type: EQUIP_TYPE.LINE,
        x: 120,
        y: 40,
        children: [],
        lineName: "",
        height: 4,
        width: 2000,
      });
    }
    elements.value = uniqBy(elements.value, "id");
    connectLines();
  }
};
onMounted(() => {});
// 处理窗口调整大小
// window.addEventListener("resize", connectLines);
onUnmounted(() => {
  // 清理所有事件监听
  window.removeEventListener("mousemove", onMouseMove);
  window.removeEventListener("mouseup", stopDrag);
});
defineExpose({ handleSaveDragConfig });
</script>
<style lang="less" scoped>
.canvas {
  position: relative;
  width: 20000px;
  height: 2000px;
}
.canvasBlock {
  --line-color: rgba(108, 108, 108, 0.3);
  background-image: linear-gradient(90deg, var(--line-color) 3%, transparent 0),
    linear-gradient(1turn, var(--line-color) 3%, transparent 0);
  background-position: 100% 100%;
  background-size: 20px 20px; /* 控制网格密度 */

  width: 20000px;
  height: 2000px;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  display: none;
}
.showGrid {
  display: block;
}
.topContent {
  height: 120px;
  line-height: 79px;
  position: absolute;
  left: 0;
  width: 100%;
}
.topIcon {
  background: url(/src/assets/drag/dianWang.png) no-repeat center center;
  width: 50px;
  height: 50px;
  left: 48px;
  top: 5px;
  position: absolute;
}
.topLine {
  top: 90px;
  left: 120px;
  width: 100%;
  height: 4px;
  background: red;
  position: absolute;
}
.topLineName {
  left: 118px;
  top: 35px;
  display: inline-block;
  position: absolute;
  width: 500px;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
  text-align: left;
}
.canvas-element {
  position: absolute;
  cursor: move;
  background-color: #202020;
}
.closeButton {
  position: absolute;
  top: 0;
  right: 0;
  background: #333;
  color: white;
  border: none;
  font-size: 12px;
}
.closeButtonLine {
  left: -15px;
  top: -7px;
  background: none;
  width: 20px;
  height: 20px;
}
.jiZhuangXiangcloseButton {
  right: 5px;
  position: absolute;
  top: 5px;
  background: #333;
  color: white;
  border: none;
  font-size: 12px;
}
.canvasTitle {
  position: absolute;
  top: -28px;
  width: 100px;
  left: 415px;
  color: #fff;
}
.canvasElementName {
  position: absolute;
  right: -120px;
  bottom: 0;
  width: 120px;
  pointer-events: none;
}
.canvasElementTips {
  position: absolute;
  left: 0px;
  bottom: -24px;
  width: 150px;
  pointer-events: none;
  color: red;
  font-size: 12px;
}

.canvasElementTip {
  position: absolute;
  right: -120px;
  bottom: -50px;
  width: 120px;
  pointer-events: none;
}
.cdzTips {
  left: 300px;
  bottom: 0;
}
.nameInput {
  width: 90px;
}
.pointerEventNone {
  pointer-events: none;
  cursor: default;
}
.isChildEquip {
  background-size: 70% !important;
  background-position: center center !important;
}
.customLineBar {
  // width: 20000px;
  background: none;
}
.customLine {
  width: 200px;
  height: 4px;
  background: red;
  display: block;
}
.line {
  position: relative;
  .lineName {
    position: absolute;
    bottom: 10px;
  }
}
.chongDianZhuang {
  width: 300px;
  height: 150px;
  background-position: center center;
}
.jiZhuangXiang {
  background-position: center center;
}

.jiZhuangXiangWithClusters {
  position: relative;
}

.jiZhuangXiangBorder {
  position: absolute;
  top: -60px;
  left: 0;
  right: 0;
  bottom: -20px;
  border: 1px solid #ff4d4f;
  border-radius: 8px;
  // pointer-events: none;
}

.jiZhuangXiangTitle {
  position: absolute;
  top: -25px;
  left: -103px;
  color: #fff;
  border-radius: 4px;
  width: 120px;
  text-align: right;
}

.jiZhuangXiangDeleteBtn {
  position: absolute;
  top: -8px;
  right: -8px;
  background: #ff4d4f;
  color: white;
  border-radius: 50%;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  pointer-events: auto;
  font-size: 12px;
  z-index: 10;
}

.jiZhuangXiangDeleteBtn:hover {
  background: #ff7875;
}
.name {
  position: absolute;
  width: 120px;
}
.linkName {
  left: 16px;
  top: -37px;
  text-align: right;
}
.blockName1 {
  left: -125px;
  top: 60px;
  text-align: right;
}
.blockName2 {
  left: 300px;
  top: 60px;
}
.charge1 {
  left: 0;
  top: 158px;
  text-align: center;
}
.charge2 {
  left: 180px;
  top: 158px;
  text-align: center;
}
.batteryClusterWrapper {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  position: absolute;
  left: 50%;
  top: 60px;
  transform: translateX(-50%);
  margin-left: 25px;
  width: auto;
  height: 80px;
}
.batteryCluster {
  position: relative;
  width: 50px;
  height: 80px;
  background-size: contain;
  background-repeat: no-repeat;
  margin: 0 25px;
  text-align: center;
  cursor: pointer;
  background-color: #202020;
  pointer-events: none;
}

.batteryClusterLabel {
  color: #fff;
  margin-top: 60px;
  font-size: 14px;
}
</style>